home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / src-server / xlisp / xlread.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-04  |  19.3 KB  |  905 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         xlread.c
  5. * RCS:          $Header: xlread.c,v 1.5 91/03/24 22:25:24 mayer Exp $
  6. * Description:  xlisp expression input routine
  7. * Author:       David Michael Betz
  8. * Created:      
  9. * Modified:     Fri Oct  4 04:09:40 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: xlread.c,v 1.5 91/03/24 22:25:24 mayer Exp $";
  42.  
  43.  
  44. #include "xlisp.h"
  45.  
  46. /* symbol parser modes */
  47. #define DONE    0
  48. #define NORMAL    1
  49. #define ESCAPE    2
  50.  
  51. /* external variables */
  52. extern LVAL s_stdout,true,s_dot;
  53. extern LVAL s_quote,s_function,s_bquote,s_comma,s_comat;
  54. extern LVAL s_rtable,k_wspace,k_const,k_nmacro,k_tmacro;
  55. extern LVAL k_sescape,k_mescape;
  56. extern char buf[];
  57.  
  58. /* external routines */
  59. extern FILE *osaopen();
  60. extern double atof();
  61. extern ITYPE;
  62.  
  63. #define WSPACE "\t \f\r\n"
  64. #define CONST1 "!$%&*+-./0123456789:<=>?@[]^_{}~"
  65. #define CONST2 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  66.  
  67. /* forward declarations */
  68. LOCAL FORWARD LVAL callmacro();    /* NPM: changed this to LOCAL */
  69. LOCAL FORWARD LVAL psymbol(),punintern(); /* NPM: changed this to LOCAL */
  70. LOCAL FORWARD LVAL pnumber(),pquote(),plist(),pvector(),pstruct(); /* NPM: changed this to LOCAL */
  71. LOCAL FORWARD LVAL readlist();    /* NPM: changed this to LOCAL */
  72. FORWARD LVAL tentry();
  73.  
  74. /* xlload - load a file of xlisp expressions */
  75. int xlload(fname,vflag,pflag)
  76.   char *fname; int vflag,pflag;
  77. {
  78.     char fullname[STRMAX+1];
  79.     LVAL fptr,expr;
  80.     CONTEXT cntxt;
  81.     FILE *fp;
  82.     int sts;
  83.  
  84.     /* protect some pointers */
  85.     xlstkcheck(2);
  86.     xlsave(fptr);
  87.     xlsave(expr);
  88.  
  89.     /* default the extension */
  90.     if (needsextension(fname)) {
  91.     strcpy(fullname,fname);
  92.     strcat(fullname,".lsp");
  93.     fname = fullname;
  94.     }
  95.  
  96.     /* allocate a file node */
  97.     fptr = cvfile(NULL);
  98.  
  99.     /* open the file */
  100.     if ((fp = osaopen(fname,"r")) == NULL) {
  101.     xlpopn(2);
  102.     return (FALSE);
  103.     }
  104.     setfile(fptr,fp);
  105.  
  106.     /* print the information line */
  107.     if (vflag)
  108.     { sprintf(buf,"; loading \"%s\"\n",fname); stdputstr(buf); }
  109.  
  110.     /* read, evaluate and possibly print each expression in the file */
  111.     xlbegin(&cntxt,CF_ERROR,true);
  112.     if (setjmp(cntxt.c_jmpbuf))
  113.     sts = FALSE;
  114.     else {
  115.     while (xlread(fptr,&expr,FALSE)) {
  116.         expr = xleval(expr);
  117.         if (pflag)
  118.         stdprint(expr);
  119.     }
  120.     sts = TRUE;
  121.     }
  122.     xlend(&cntxt);
  123.  
  124.     /* close the file */
  125.     osclose(getfile(fptr));
  126.     setfile(fptr,NULL);
  127.  
  128.     /* restore the stack */
  129.     xlpopn(2);
  130.  
  131.     /* return status */
  132.     return (sts);
  133. }
  134.  
  135. /* xlread - read an xlisp expression */
  136. int xlread(fptr,pval,rflag)
  137.   LVAL fptr,*pval; int rflag;
  138. {
  139.     int sts;
  140.  
  141.     /* read an expression */
  142.     while ((sts = readone(fptr,pval)) == FALSE)
  143.     ;
  144.  
  145.     /* return status */
  146.     return (sts == EOF ? FALSE : TRUE);
  147. }
  148.  
  149. /* readone - attempt to read a single expression */
  150. int readone(fptr,pval)
  151.   LVAL fptr,*pval;
  152. {
  153.     LVAL val,type;
  154.     int ch;
  155.  
  156.     /* get a character and check for EOF */
  157.     if ((ch = xlgetc(fptr)) == EOF)
  158.     return (EOF);
  159.  
  160.     /* handle white space */
  161.     if ((type = tentry(ch)) == k_wspace)
  162.     return (FALSE);
  163.  
  164.     /* handle symbol constituents */
  165.     else if (type == k_const) {
  166.     xlungetc(fptr,ch);
  167.     *pval = psymbol(fptr);
  168.     return (TRUE);        
  169.     }
  170.  
  171.     /* handle single and multiple escapes */
  172.     else if (type == k_sescape || type == k_mescape) {
  173.     xlungetc(fptr,ch);
  174.     *pval = psymbol(fptr);
  175.     return (TRUE);
  176.     }
  177.     
  178.     /* handle read macros */
  179.     else if (consp(type)) {
  180.     if ((val = callmacro(fptr,ch)) && consp(val)) {
  181.         *pval = car(val);
  182.         return (TRUE);
  183.     }
  184.     else
  185.         return (FALSE);
  186.     }
  187.  
  188.     /* handle illegal characters */
  189.     else
  190.     xlerror("illegal character",cvfixnum((FIXTYPE)ch));
  191. }
  192.  
  193. /* rmhash - read macro for '#' */
  194. LVAL rmhash()
  195. {
  196.     LVAL fptr,mch,val;
  197.     int escflag,ch;
  198.  
  199.     /* protect some pointers */
  200.     xlsave1(val);
  201.  
  202.     /* get the file and macro character */
  203.     fptr = xlgetfile();
  204.     mch = xlgachar();
  205.     xllastarg();
  206.  
  207.     /* make the return value */
  208.     val = consa(NIL);
  209.  
  210.     /* check the next character */
  211.     switch (ch = xlgetc(fptr)) {
  212.     case '\'':
  213.         rplaca(val,pquote(fptr,s_function));
  214.         break;
  215.     case '(':
  216.         xlungetc(fptr,ch);
  217.         rplaca(val,pvector(fptr));
  218.         break;
  219.     case 'b':
  220.     case 'B':
  221.         rplaca(val,pnumber(fptr,2));
  222.         break;
  223.     case 'o':
  224.     case 'O':
  225.         rplaca(val,pnumber(fptr,8));
  226.         break;
  227.     case 'x':
  228.     case 'X':
  229.             rplaca(val,pnumber(fptr,16));
  230.         break;
  231.     case 's':
  232.     case 'S':
  233.         rplaca(val,pstruct(fptr));
  234.         break;
  235.     case '\\':
  236.         xlungetc(fptr,ch);
  237.         pname(fptr,&escflag);
  238.         ch = buf[0];
  239.         if (strlen(buf) > 1) {
  240.             upcase(buf);
  241.             if (strcmp(buf,"NEWLINE") == 0)
  242.             ch = '\n';
  243.             else if (strcmp(buf,"SPACE") == 0)
  244.             ch = ' ';
  245.             else
  246.             xlerror("unknown character name",cvstring(buf));
  247.         }
  248.         rplaca(val,cvchar(ch));
  249.         break;
  250.     case ':':
  251.             rplaca(val,punintern(fptr));
  252.         break;
  253.     case '|':
  254.             pcomment(fptr);
  255.         val = NIL;
  256.         break;
  257.     default:
  258.         xlerror("illegal character after #",cvfixnum((FIXTYPE)ch));
  259.     }
  260.  
  261.     /* restore the stack */
  262.     xlpop();
  263.  
  264.     /* return the value */
  265.     return (val);
  266. }
  267.  
  268. /* rmquote - read macro for '\'' */
  269. LVAL rmquote()
  270. {
  271.     LVAL fptr,mch;
  272.  
  273.     /* get the file and macro character */
  274.     fptr = xlgetfile();
  275.     mch = xlgachar();
  276.     xllastarg();
  277.  
  278.     /* parse the quoted expression */
  279.     return (consa(pquote(fptr,s_quote)));
  280. }
  281.  
  282. /* rmdquote - read macro for '"' */
  283. LVAL rmdquote()
  284. {
  285.     unsigned char buf[STRMAX+1],*p,*sptr;
  286.     LVAL fptr,str,newstr,mch;
  287.     int len,blen,ch,d2,d3;
  288.  
  289.     /* protect some pointers */
  290.     xlsave1(str);
  291.  
  292.     /* get the file and macro character */
  293.     fptr = xlgetfile();
  294.     mch = xlgachar();
  295.     xllastarg();
  296.  
  297.     /* loop looking for a closing quote */
  298.     len = blen = 0; p = buf;
  299.     while ((ch = checkeof(fptr)) != '"') {
  300.  
  301.     /* handle escaped characters */
  302.     switch (ch) {
  303.     case '\\':
  304.         switch (ch = checkeof(fptr)) {
  305.         case 't':
  306.             ch = '\011';
  307.             break;
  308.         case 'n':
  309.             ch = '\012';
  310.             break;
  311.         case 'f':
  312.             ch = '\014';
  313.             break;
  314.         case 'r':
  315.             ch = '\015';
  316.             break;
  317.         default:
  318.             if (ch >= '0' && ch <= '7') {
  319.                 d2 = checkeof(fptr);
  320.                 d3 = checkeof(fptr);
  321.                 if (d2 < '0' || d2 > '7'
  322.                  || d3 < '0' || d3 > '7')
  323.                 xlfail("invalid octal digit");
  324.                 ch -= '0'; d2 -= '0'; d3 -= '0';
  325.                 ch = (ch << 6) | (d2 << 3) | d3;
  326.             }
  327.             break;
  328.         }
  329.     }
  330.  
  331.     /* check for buffer overflow */
  332.     if (blen >= STRMAX) {
  333.          newstr = newstring(len + STRMAX + 1);
  334.         sptr = getstring(newstr); *sptr = '\0';
  335.         if (str) strcat(sptr,getstring(str));
  336.         *p = '\0'; strcat(sptr,buf);
  337.         p = buf; blen = 0;
  338.         len += STRMAX;
  339.         str = newstr;
  340.     }
  341.  
  342.     /* store the character */
  343.     *p++ = ch; ++blen;
  344.     }
  345.  
  346.     /* append the last substring */
  347.     if (str == NIL || blen) {
  348.     newstr = newstring(len + blen + 1);
  349.     sptr = getstring(newstr); *sptr = '\0';
  350.     if (str) strcat(sptr,getstring(str));
  351.     *p = '\0'; strcat(sptr,buf);
  352.     str = newstr;
  353.     }
  354.  
  355.     /* restore the stack */
  356.     xlpop();
  357.  
  358.     /* return the new string */
  359.     return (consa(str));
  360. }
  361.  
  362. /* rmbquote - read macro for '`' */
  363. LVAL rmbquote()
  364. {
  365.     LVAL fptr,mch;
  366.  
  367.     /* get the file and macro character */
  368.     fptr = xlgetfile();
  369.     mch = xlgachar();
  370.     xllastarg();
  371.  
  372.     /* parse the quoted expression */
  373.     return (consa(pquote(fptr,s_bquote)));
  374. }
  375.  
  376. /* rmcomma - read macro for ',' */
  377. LVAL rmcomma()
  378. {
  379.     LVAL fptr,mch,sym;
  380.     int ch;
  381.  
  382.     /* get the file and macro character */
  383.     fptr = xlgetfile();
  384.     mch = xlgachar();
  385.     xllastarg();
  386.  
  387.     /* check the next character */
  388.     if ((ch = xlgetc(fptr)) == '@')
  389.     sym = s_comat;
  390.     else {
  391.     xlungetc(fptr,ch);
  392.     sym = s_comma;
  393.     }
  394.  
  395.     /* make the return value */
  396.     return (consa(pquote(fptr,sym)));
  397. }
  398.  
  399. /* rmlpar - read macro for '(' */
  400. LVAL rmlpar()
  401. {
  402.     LVAL fptr,mch;
  403.  
  404.     /* get the file and macro character */
  405.     fptr = xlgetfile();
  406.     mch = xlgachar();
  407.     xllastarg();
  408.  
  409.     /* make the return value */
  410.     return (consa(plist(fptr)));
  411. }
  412.  
  413. /* rmrpar - read macro for ')' */
  414. LVAL rmrpar()
  415. {
  416.     xlfail("misplaced right paren");
  417. }
  418.  
  419. /* rmsemi - read macro for ';' */
  420. LVAL rmsemi()
  421. {
  422.     LVAL fptr,mch;
  423.     int ch;
  424.  
  425.     /* get the file and macro character */
  426.     fptr = xlgetfile();
  427.     mch = xlgachar();
  428.     xllastarg();
  429.  
  430.     /* skip to end of line */
  431.     while ((ch = xlgetc(fptr)) != EOF && ch != '\n')
  432.     ;
  433.  
  434.     /* return nil (nothing read) */
  435.     return (NIL);
  436. }
  437.  
  438. /* pcomment - parse a comment delimited by #| and |# */
  439. LOCAL pcomment(fptr)
  440.   LVAL fptr;
  441. {
  442.     int lastch,ch,n;
  443.  
  444.     /* look for the matching delimiter (and handle nesting) */
  445.     for (n = 1, lastch = -1; n > 0 && (ch = xlgetc(fptr)) != EOF; ) {
  446.     if (lastch == '|' && ch == '#')
  447.         { --n; ch = -1; }
  448.     else if (lastch == '#' && ch == '|')
  449.         { ++n; ch = -1; }
  450.     lastch = ch;
  451.     }
  452. }
  453.  
  454. /* pnumber - parse a number */
  455. LOCAL LVAL pnumber(fptr,radix)
  456.   LVAL fptr; int radix;
  457. {
  458.     int digit,ch;
  459.     long num;
  460.     
  461.     for (num = 0L; (ch = xlgetc(fptr)) != EOF; ) {
  462.     if (islower(ch)) ch = toupper(ch);
  463.     if (!('0' <= ch && ch <= '9') && !('A' <= ch && ch <= 'F'))
  464.         break;
  465.     if ((digit = (ch <= '9' ? ch - '0' : ch - 'A' + 10)) >= radix)
  466.         break;
  467.     num = num * (long)radix + (long)digit;
  468.     }
  469.     xlungetc(fptr,ch);
  470.     return (cvfixnum((FIXTYPE)num));
  471. }
  472.  
  473. /* plist - parse a list */
  474. LOCAL LVAL plist(fptr)
  475.   LVAL fptr;
  476. {
  477.     LVAL val,expr,lastnptr,nptr;
  478.  
  479.     /* protect some pointers */
  480.     xlstkcheck(2);
  481.     xlsave(val);
  482.     xlsave(expr);
  483.  
  484.     /* keep appending nodes until a closing paren is found */
  485.     for (lastnptr = NIL; nextch(fptr) != ')'; )
  486.  
  487.     /* get the next expression */
  488.     switch (readone(fptr,&expr)) {
  489.     case EOF:
  490.         badeof(fptr);
  491.     case TRUE:
  492.  
  493.         /* check for a dotted tail */
  494.         if (expr == s_dot) {
  495.  
  496.         /* make sure there's a node */
  497.         if (lastnptr == NIL)
  498.             xlfail("invalid dotted pair");
  499.  
  500.         /* parse the expression after the dot */
  501.         if (!xlread(fptr,&expr,TRUE))
  502.             badeof(fptr);
  503.         rplacd(lastnptr,expr);
  504.  
  505.         /* make sure its followed by a close paren */
  506.         if (nextch(fptr) != ')')
  507.             xlfail("invalid dotted pair");
  508.         }
  509.  
  510.         /* otherwise, handle a normal list element */
  511.         else {
  512.         nptr = consa(expr);
  513.         if (lastnptr == NIL)
  514.             val = nptr;
  515.         else
  516.             rplacd(lastnptr,nptr);
  517.         lastnptr = nptr;
  518.         }
  519.         break;
  520.     }
  521.  
  522.     /* skip the closing paren */
  523.     xlgetc(fptr);
  524.  
  525.     /* restore the stack */
  526.     xlpopn(2);
  527.  
  528.     /* return successfully */
  529.     return (val);
  530. }
  531.  
  532. /* pvector - parse a vector */
  533. LOCAL LVAL pvector(fptr)
  534.   LVAL fptr;
  535. {
  536.     LVAL list,val;
  537.     int len,i;
  538.  
  539.     /* protect some pointers */
  540.     xlsave1(list);
  541.  
  542.     /* read the list */
  543.     list = readlist(fptr,&len);
  544.  
  545.     /* make a vector of the appropriate length */
  546.     val = newvector(len);
  547.  
  548.     /* copy the list into the vector */
  549.     for (i = 0; i < len; ++i, list = cdr(list))
  550.     setelement(val,i,car(list));
  551.  
  552.     /* restore the stack */
  553.     xlpop();
  554.  
  555.     /* return successfully */
  556.     return (val);
  557. }
  558.  
  559. /* pstruct - parse a structure */
  560. LOCAL LVAL pstruct(fptr)
  561.   LVAL fptr;
  562. {
  563.     extern LVAL xlrdstruct();
  564.     LVAL list,val;
  565.     int len;
  566.  
  567.     /* protect some pointers */
  568.     xlsave1(list);
  569.  
  570.     /* read the list */
  571.     list = readlist(fptr,&len);
  572.  
  573.     /* make the structure */
  574.     val = xlrdstruct(list);
  575.  
  576.     /* restore the stack */
  577.     xlpop();
  578.  
  579.     /* return successfully */
  580.     return (val);
  581. }
  582.  
  583. /* pquote - parse a quoted expression */
  584. LOCAL LVAL pquote(fptr,sym)
  585.   LVAL fptr,sym;
  586. {
  587.     LVAL val,p;
  588.  
  589.     /* protect some pointers */
  590.     xlsave1(val);
  591.  
  592.     /* allocate two nodes */
  593.     val = consa(sym);
  594.     rplacd(val,consa(NIL));
  595.  
  596.     /* initialize the second to point to the quoted expression */
  597.     if (!xlread(fptr,&p,TRUE))
  598.     badeof(fptr);
  599.     rplaca(cdr(val),p);
  600.  
  601.     /* restore the stack */
  602.     xlpop();
  603.  
  604.     /* return the quoted expression */
  605.     return (val);
  606. }
  607.  
  608. /* psymbol - parse a symbol name */
  609. LOCAL LVAL psymbol(fptr)
  610.   LVAL fptr;
  611. {
  612.     int escflag;
  613.     LVAL val;
  614.     pname(fptr,&escflag);
  615.     return (escflag || !isnumber(buf,&val) ? xlenter(buf) : val);
  616. }
  617.  
  618. /* punintern - parse an uninterned symbol */
  619. LOCAL LVAL punintern(fptr)
  620.   LVAL fptr;
  621. {
  622.     int escflag;
  623.     pname(fptr,&escflag);
  624.     return (xlmakesym(buf));
  625. }
  626.  
  627. /* pname - parse a symbol/package name */
  628. LOCAL int pname(fptr,pescflag)
  629.   LVAL fptr; int *pescflag;
  630. {
  631.     int mode,ch,i;
  632.     LVAL type;
  633.  
  634.     /* initialize */
  635.     *pescflag = FALSE;
  636.     mode = NORMAL;
  637.     i = 0;
  638.  
  639.     /* accumulate the symbol name */
  640.     while (mode != DONE) {
  641.  
  642.     /* handle normal mode */
  643.     while (mode == NORMAL)
  644.         if ((ch = xlgetc(fptr)) == EOF)
  645.         mode = DONE;
  646.         else if ((type = tentry(ch)) == k_sescape) {
  647.         i = storech(buf,i,checkeof(fptr));
  648.         *pescflag = TRUE;
  649.         }
  650.         else if (type == k_mescape) {
  651.         *pescflag = TRUE;
  652.         mode = ESCAPE;
  653.         }
  654.         else if (type == k_const
  655.          ||  (consp(type) && car(type) == k_nmacro))
  656.         i = storech(buf,i,islower(ch) ? toupper(ch) : ch);
  657.         else
  658.         mode = DONE;
  659.  
  660.     /* handle multiple escape mode */
  661.     while (mode == ESCAPE)
  662.         if ((ch = xlgetc(fptr)) == EOF)
  663.         badeof(fptr);
  664.         else if ((type = tentry(ch)) == k_sescape)
  665.         i = storech(buf,i,checkeof(fptr));
  666.         else if (type == k_mescape)
  667.         mode = NORMAL;
  668.         else
  669.         i = storech(buf,i,ch);
  670.     }
  671.     buf[i] = 0;
  672.  
  673.     /* check for a zero length name */
  674.     if (i == 0)
  675.     xlerror("zero length name");
  676.  
  677.     /* unget the last character and return it */
  678.     xlungetc(fptr,ch);
  679.     return (ch);
  680. }
  681.  
  682. /* readlist - read a list terminated by a ')' */
  683. LOCAL LVAL readlist(fptr,plen)
  684.   LVAL fptr; int *plen;
  685. {
  686.     LVAL list,expr,lastnptr,nptr;
  687.     int ch;
  688.  
  689.     /* protect some pointers */
  690.     xlstkcheck(2);
  691.     xlsave(list);
  692.     xlsave(expr);
  693.  
  694.     /* get the open paren */
  695.     if ((ch = nextch(fptr)) != '(')
  696.     xlfail("expecting an open paren");
  697.     xlgetc(fptr);
  698.  
  699.     /* keep appending nodes until a closing paren is found */
  700.     for (lastnptr = NIL, *plen = 0; (ch = nextch(fptr)) != ')'; ) {
  701.  
  702.     /* check for end of file */
  703.     if (ch == EOF)
  704.         badeof(fptr);
  705.  
  706.     /* get the next expression */
  707.     switch (readone(fptr,&expr)) {
  708.     case EOF:
  709.         badeof(fptr);
  710.     case TRUE:
  711.         nptr = consa(expr);
  712.         if (lastnptr == NIL)
  713.         list = nptr;
  714.         else
  715.         rplacd(lastnptr,nptr);
  716.         lastnptr = nptr;
  717.         ++(*plen);
  718.         break;
  719.     }
  720.     }
  721.  
  722.     /* skip the closing paren */
  723.     xlgetc(fptr);
  724.  
  725.     /* restore the stack */
  726.     xlpopn(2);
  727.  
  728.     /* return the list */
  729.     return (list);
  730. }
  731.  
  732. /* storech - store a character in the print name buffer */
  733. LOCAL int storech(buf,i,ch)
  734.   char *buf; int i,ch;
  735. {
  736.     if (i < STRMAX)
  737.     buf[i++] = ch;
  738.     return (i);
  739. }
  740.  
  741. /* tentry - get a readtable entry */
  742. LVAL tentry(ch)
  743.   int ch;
  744. {
  745.     LVAL rtable;
  746.     rtable = getvalue(s_rtable);
  747.     if (!vectorp(rtable) || ch < 0 || ch >= getsize(rtable))
  748.     return (NIL);
  749.     return (getelement(rtable,ch));
  750. }
  751.  
  752. /* nextch - look at the next non-blank character */
  753. LOCAL int nextch(fptr)
  754.   LVAL fptr;
  755. {
  756.     int ch;
  757.  
  758.     /* return and save the next non-blank character */
  759.     while ((ch = xlgetc(fptr)) != EOF && isspace(ch))
  760.     ;
  761.     xlungetc(fptr,ch);
  762.     return (ch);
  763. }
  764.  
  765. /* checkeof - get a character and check for end of file */
  766. LOCAL int checkeof(fptr)
  767.   LVAL fptr;
  768. {
  769.     int ch;
  770.  
  771.     if ((ch = xlgetc(fptr)) == EOF)
  772.     badeof(fptr);
  773.     return (ch);
  774. }
  775.  
  776. /* badeof - unexpected eof */
  777. LOCAL badeof(fptr)
  778.   LVAL fptr;
  779. {
  780.     xlgetc(fptr);
  781.     xlfail("unexpected EOF");
  782. }
  783.  
  784. /* isnumber - check if this string is a number */
  785. int isnumber(str,pval)
  786.   char *str; LVAL *pval;
  787. {
  788.     int dl,dr;
  789.     char *p;
  790.  
  791.     /* initialize */
  792.     p = str; dl = dr = 0;
  793.  
  794.     /* check for a sign */
  795.     if (*p == '+' || *p == '-')
  796.     p++;
  797.  
  798.     /* check for a string of digits */
  799.     while (isdigit(*p))
  800.     p++, dl++;
  801.  
  802.     /* check for a decimal point */
  803.     if (*p == '.') {
  804.     p++;
  805.     while (isdigit(*p))
  806.         p++, dr++;
  807.     }
  808.  
  809.     /* check for an exponent */
  810.     if ((dl || dr) && *p == 'E') {
  811.     p++;
  812.  
  813.     /* check for a sign */
  814.     if (*p == '+' || *p == '-')
  815.         p++;
  816.  
  817.     /* check for a string of digits */
  818.     while (isdigit(*p))
  819.         p++, dr++;
  820.     }
  821.  
  822.     /* make sure there was at least one digit and this is the end */
  823.     if ((dl == 0 && dr == 0) || *p)
  824.     return (FALSE);
  825.  
  826.     /* convert the string to an integer and return successfully */
  827.     if (pval) {
  828.     if (*str == '+') ++str;
  829.     if (str[strlen(str)-1] == '.') str[strlen(str)-1] = 0;
  830.     *pval = (dr ? cvflonum(atof(str)) : cvfixnum(ICNV(str)));
  831.     }
  832.     return (TRUE);
  833. }
  834.  
  835. /* defmacro - define a read macro */
  836. defmacro(ch,type,offset)
  837.   int ch; LVAL type; int offset;
  838. {
  839.     extern FUNDEF funtab[];
  840.     LVAL subr;
  841.     subr = cvsubr(funtab[offset].fd_subr,funtab[offset].fd_type,offset);
  842.     setelement(getvalue(s_rtable),ch,cons(type,subr));
  843. }
  844.  
  845. /* callmacro - call a read macro */
  846. LOCAL LVAL callmacro(fptr,ch)    /* NPM: changed this to LOCAL */
  847.   LVAL fptr; int ch;
  848. {
  849.     LVAL *newfp;
  850.  
  851.     /* create the new call frame */
  852.     newfp = xlsp;
  853.     pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  854.     pusharg(cdr(getelement(getvalue(s_rtable),ch)));
  855.     pusharg(cvfixnum((FIXTYPE)2));
  856.     pusharg(fptr);
  857.     pusharg(cvchar(ch));
  858.     xlfp = newfp;
  859.     return (xlapply(2));
  860. }
  861.  
  862. /* upcase - translate a string to upper case */
  863. LOCAL upcase(str)
  864.   unsigned char *str;
  865. {
  866.     for (; *str != '\0'; ++str)
  867.     if (islower(*str))
  868.         *str = toupper(*str);
  869. }
  870.  
  871. /* xlrinit - initialize the reader */
  872. xlrinit()
  873. {
  874.     LVAL rtable;
  875.     char *p;
  876.     int ch;
  877.  
  878.     /* create the read table */
  879.     rtable = newvector(256);
  880.     setvalue(s_rtable,rtable);
  881.  
  882.     /* initialize the readtable */
  883.     for (p = WSPACE; ch = *p++; )
  884.     setelement(rtable,ch,k_wspace);
  885.     for (p = CONST1; ch = *p++; )
  886.     setelement(rtable,ch,k_const);
  887.     for (p = CONST2; ch = *p++; )
  888.     setelement(rtable,ch,k_const);
  889.  
  890.     /* setup the escape characters */
  891.     setelement(rtable,'\\',k_sescape);
  892.     setelement(rtable,'|', k_mescape);
  893.  
  894.     /* install the read macros */
  895.     defmacro('#', k_nmacro,FT_RMHASH);
  896.     defmacro('\'',k_tmacro,FT_RMQUOTE);
  897.     defmacro('"', k_tmacro,FT_RMDQUOTE);
  898.     defmacro('`', k_tmacro,FT_RMBQUOTE);
  899.     defmacro(',', k_tmacro,FT_RMCOMMA);
  900.     defmacro('(', k_tmacro,FT_RMLPAR);
  901.     defmacro(')', k_tmacro,FT_RMRPAR);
  902.     defmacro(';', k_tmacro,FT_RMSEMI);
  903. }
  904.